package vip.zywork.datascope.interceptor;

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectBody;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.util.StringUtils;
import vip.zywork.datascope.annotation.MyDataScope;
import vip.zywork.datascope.common.MyConstant;
import vip.zywork.datascope.common.MyPluginUtils;
import vip.zywork.datascope.enums.MyDataScopeType;
import vip.zywork.datascope.support.DadaScopeParameterHolder;
import vip.zywork.datascope.support.DadaScopeTypeHolder;
import vip.zywork.datascope.support.MyDataScopeHandler;
import vip.zywork.datascope.support.MyJsqlParserSupport;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Objects;

/**
 * <p>  </p>
 *
 * @author ZHANG_YANG
 * @version 1.0
 * @date 2021/10/6 16:40
 * @since
 */
public abstract class AbstractMyDataScopeInterceptor extends MyJsqlParserSupport implements MyInterceptor{

    protected static int EQUAL = 0;
    private MyDataScopeHandler dataScopeHandler;

    public AbstractMyDataScopeInterceptor(MyDataScopeHandler dataScopeHandler) {
        this.dataScopeHandler = dataScopeHandler;
    }


    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException, JSQLParserException, ClassNotFoundException {
        if (dataScopeHandler.isAdmin()) {
            return;
        }
        this.handle(ms,boundSql);
    }

    /**
     * 处理sql
     * @param ms
     * @param boundSql
     * @throws ClassNotFoundException
     * @throws JSQLParserException
     */
    protected void handle(MappedStatement ms,BoundSql boundSql) throws ClassNotFoundException, JSQLParserException {
        String namespace  = ms.getId();
        //获取mapper名称
        String className = namespace.substring(0,namespace.lastIndexOf("."));
        //注解逻辑判断  添加注解了才拦截
        Class<?> classType = Class.forName(className);
        // 获取方法名
        String methodName = namespace .substring(namespace .lastIndexOf(".") + 1);
        // 获取当前mapper 的所有方法
        Method[] methods = classType.getDeclaredMethods();
        // 遍历mapper所有方法，找到加了@MyDataScope注解的方法，然后修改sql
        for (Method method : methods) {
            if (method.isAnnotationPresent(MyDataScope.class) && methodName.equals(method.getName())) {
                MyDataScope myDataScope = method.getAnnotation(MyDataScope.class);
                if (!myDataScope.ignore()) {
                    // 在此处修改sql
                    MyPluginUtils.MPBoundSql mpBs = MyPluginUtils.mpBoundSql(boundSql);
                    MyDataScopeType scope = myDataScope.scope();
                    String s = myDataScope.customScope();
                    if (StringUtils.hasLength(s)){
                        mpBs.sql(super.parserSingle(mpBs.sql(), s));
                    }else {
                        mpBs.sql(super.parserSingle(mpBs.sql(), scope));
                    }
                }
            }
        }
        DadaScopeTypeHolder.clear();
        DadaScopeParameterHolder.clear();
    }
    /**
     * 修改sql
     * @param select
     * @param index
     * @param obj
     */
    @Override
    protected void processSelect(Select select, int index, String sql, Object obj){
        this.processSelectBody(select.getSelectBody(),obj);
    }
    protected void processSelectBody(SelectBody selectBody, Object obj) {
        if (selectBody == null) {
            return;
        }
        if (selectBody instanceof PlainSelect) {
            this.processPlainSelect((PlainSelect) selectBody,obj);
        }
    }
    protected void processPlainSelect(PlainSelect plainSelect,Object obj) {
        FromItem fromItem = plainSelect.getFromItem();
        Expression where = plainSelect.getWhere();
        if (fromItem instanceof Table) {
            Table fromTable = (Table) fromItem;
            if (!dataScopeHandler.ignoreTable(fromTable.getName())) {
                plainSelect.setWhere(builderExpression(where, fromTable,obj));
            }
        }
    }

    /**
     * 处理条件
     * @param currentExpression
     * @param fromTable
     * @param obj
     * @return
     */
    protected abstract Expression builderExpression(Expression currentExpression, Table fromTable,Object obj);

    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {

    }

    /**
     * 字段别名设置
     * <p>tenantId 或 tableAlias.tenantId</p>
     *
     * @param table 表对象
     * @return 字段
     */
    protected Column getAliasColumn(Table table) {
        StringBuilder column = new StringBuilder();
        if (table.getAlias() != null) {
            column.append(table.getAlias().getName()).append(MyConstant.DOT);
        }
        column.append(dataScopeHandler.getDeptIdColumn());
        return new Column(column.toString());
    }


    protected MyDataScopeHandler getDataScopeHandler() {
        return dataScopeHandler;
    }

    public void setDataScopeHandler(MyDataScopeHandler dataScopeHandler) {
        this.dataScopeHandler = dataScopeHandler;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof AbstractMyDataScopeInterceptor)) {
            return false;
        }
        AbstractMyDataScopeInterceptor that = (AbstractMyDataScopeInterceptor) o;
        return Objects.equals(getDataScopeHandler(), that.getDataScopeHandler());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getDataScopeHandler());
    }
    //    protected void processType(MyDataScopeType type,BoundSql boundSql) throws JSQLParserException {
//        MyPluginUtils.MPBoundSql mpBs = MyPluginUtils.mpBoundSql(boundSql);
//        Statement statement = CCJSqlParserUtil.parse(mpBs.sql());
//        if (statement instanceof Select){
//            Select select = (Select)statement;
//            SelectBody selectBody = select.getSelectBody();
//            if (selectBody instanceof PlainSelect){
//                PlainSelect plainSelect = (PlainSelect)selectBody;
//                FromItem fromItem = plainSelect.getFromItem();
//                if (fromItem instanceof Table) {
//                    Table fromTable = (Table) fromItem;
//                    Column aliasColumn = this.getAliasColumn(fromTable);
//                    if ("3".equals(type)){
//                        ItemsList itemsList = new ExpressionList(Arrays.asList(
//                                new StringValue("1"),
//                                new StringValue("2"),
//                                new StringValue("3"),
//                                new StringValue("5")
//                        ));
//                        InExpression inExpression = new InExpression(aliasColumn, itemsList);
//                        mpBs.sql(parserSingle(mpBs.sql(), inExpression));
//                    }
//                }
//            }
//        }
//    }

//    /**
//     * 修改sql
//     * @param select
//     * @param index
//     * @param obj
//     */
//    @Override
//    protected void processSelect(Select select, int index, String sql, Object obj){
//        if (obj instanceof InExpression){
//            InExpression inExpression = (InExpression)obj;
//            SelectBody selectBody = select.getSelectBody();
//            if (selectBody instanceof PlainSelect){
//                PlainSelect plainSelect = (PlainSelect)selectBody;
//                FromItem fromItem = plainSelect.getFromItem();
//                if (fromItem instanceof Table) {
//                    Table fromTable = (Table) fromItem;
//                    if (!dataScopeHandler.ignoreTable(fromTable.getName())) {
//                        if (null == plainSelect.getWhere()) {
//                            // 不存在 where 条件
//                            plainSelect.setWhere(new Parenthesis(inExpression));
//                        } else {
//                            // 存在 where 条件 and 处理
//                            plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), inExpression));
//                        }
//                    }
//                }
//            }
//        }
//    }
}
